package com.yifeng.repo.base.utils.file;

import java.io.*;
import java.util.*;
import java.util.jar.*;
import java.util.regex.Pattern;
import java.util.zip.ZipOutputStream;

import static java.io.File.separator;

/**
 * Created by daibing on 2019/11/16.
 */
public class JarHelper {

    public static Properties getProperties(File file) throws IOException {
        return fetchProperties(file, "pom.properties");
    }

    public static String getVersion(File file, String groupId, String artifactId) {
        try {
            Properties properties = getProperties(file, groupId, artifactId);
            return properties.getProperty("version");
        } catch (IOException e) {
            return null;
        }
    }

    public static Properties getProperties(File file, String groupId, String artifactId) throws IOException {
        String propertiesPath = String.format("META-INF/maven/%s/%s/pom.properties", groupId, artifactId);
        return getProperties(file, propertiesPath);
    }

    public static Properties getProperties(File file, String propertiesPath) throws IOException {
        Properties properties = new Properties();
        if (!file.exists()) {
            return properties;
        }
        JarFile jarFile = new JarFile(file);
        JarEntry propertiesJarEntry = jarFile.getJarEntry(propertiesPath);
        properties.load(jarFile.getInputStream(propertiesJarEntry));
        return properties;
    }

    public static Properties fetchProperties(File file, String propertiesName) throws IOException {
        Properties properties = new Properties();
        if (!file.exists()) {
            return properties;
        }
        JarFile jarFile = new JarFile(file);
        JarInputStream jis = new JarInputStream(new FileInputStream(file));
        JarEntry propertiesJarEntry = null;
        while (true) {
            JarEntry jarEntry = jis.getNextJarEntry();
            if (jarEntry.isDirectory()) {
                continue;
            }
            if (!(jarEntry.getName().startsWith("META-INF") || jarEntry.getName().startsWith("conf"))) {
                continue;
            }
            if (jarEntry.getName().endsWith(propertiesName)) {
                propertiesJarEntry = jarEntry;
                break;
            }
        }
        properties.load(jarFile.getInputStream(propertiesJarEntry));
        return properties;
    }

    public static String getLatest(String path, String regex) {
        final Pattern pattern = Pattern.compile(regex);
        String[] files = new File(path).list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return pattern.matcher(name).matches();
            }
        });
        if (files == null || files.length == 0) {
            return null;
        }

        List<String> list = Arrays.asList(files);
        Collections.sort(list);
        return new File(path + separator + list.get(list.size() - 1)).getAbsolutePath();
    }

    public static List<String> create(Collection<String> dirs) throws IOException {
        List<String> newJars = new ArrayList<>(dirs.size());
        for (String dir : dirs) {
            String newJar = dir + ".jar";
            File source = new File(dir);
            File target = new File(newJar);
            JarOutputStream targetJarOS = null;
            File manifestFile = new File(dir + File.separator + JarFile.MANIFEST_NAME);
            try {
                if (manifestFile.exists()) {
                    targetJarOS = new JarOutputStream(new FileOutputStream(target), new Manifest(new FileInputStream(manifestFile)));
                    manifestFile.delete();
                } else {
                    targetJarOS = new JarOutputStream(new FileOutputStream(target));
                }
                zipFile(targetJarOS, source, null);
            } finally {
                if (targetJarOS != null) {
                    targetJarOS.close();
                }
            }
            newJars.add(newJar);
        }
        return newJars;
    }

    public static List<String> extract(Collection<String> jars) throws IOException {
        List<String> newDirs = new ArrayList<>(jars.size());
        for (String jar : jars) {
            String newDir = jar.replace(".jar", "");
            File source = new File(jar);
            JarFile sourceJar = new JarFile(source);
            JarInputStream sourceJarIS = new JarInputStream(new FileInputStream(source));
            JarEntry sourceJarEntry = null;
            while ((sourceJarEntry = sourceJarIS.getNextJarEntry()) != null) {
                File target = new File(newDir + File.separator + sourceJarEntry.getName());
                if (!target.getParentFile().exists()) {
                    target.getParentFile().mkdirs();
                }
                write(sourceJar.getInputStream(sourceJarEntry), new FileOutputStream(target), true);
            }
            // Add Manifest
            Manifest manifest = sourceJarIS.getManifest();
            if (manifest != null) {
                File manifestFile = new File(newDir + File.separator + JarFile.MANIFEST_NAME);
                if (!manifestFile.getParentFile().exists()) {
                    manifestFile.getParentFile().mkdirs();
                }
                manifest.write(new FileOutputStream(manifestFile));
            }
            newDirs.add(newDir);
        }
        return newDirs;
    }

    public static void zipFile(ZipOutputStream zos, File source, String packagePath) throws IOException {
        if (source.isDirectory()) {
            File[] subSourceFiles = source.listFiles();
            if (subSourceFiles == null) {
                throw new RuntimeException("list files failed: " + source);
            }
            for (File subSourceFile : subSourceFiles) {
                String absolutePath = isBlank(packagePath) ? subSourceFile.getName() : packagePath + "/" + subSourceFile.getName();
                zipFile(zos, subSourceFile, absolutePath);
            }
            return;
        }
        if ("MANIFEST.MF".contains(source.getName())) {
            return;
        }
        // zip file
        InputStream in = new FileInputStream(source);
        zos.putNextEntry(new JarEntry(packagePath));
        write(in, zos, false);
    }

    private static void write(InputStream input, OutputStream output, boolean closeOutputStream) throws IOException {
        BufferedInputStream in = new BufferedInputStream(input);
        BufferedOutputStream out = new BufferedOutputStream(output);
        int len = -1;
        byte[] buff = new byte[1024];
        try {
            while ((len = in.read(buff)) != -1) {
                out.write(buff, 0, len);
            }
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            in.close();
            if (closeOutputStream) {
                out.close();
            }
        }
    }

    private static boolean isBlank(String s) {
        return s == null || s.trim().length() == 0;
    }

    public static void main(String[] args) throws Exception {
        System.out.println("start.");
        File file = new File("D:\\XSVN2\\SVN-FIRE\\fire-drmx\\branches\\1.0.0-dev\\client\\dist\\fire-drm-1.0.0-SNAPSHOT\\bin\\fire-drm-daemon.jar");
//        Properties properties = JarHelper.getProperties(file, "next.fire", "fire-drm-daemon");
        Properties properties = JarHelper.getProperties(file, "conf/drm-daemon-version.properties");
        System.out.println("properties" + properties);
        System.out.println(JarHelper.getVersion(file, "next.fire", "fire-drm-daemon"));
    }
}
